﻿#include "VCenterTabWidget.h"
#include "VFunctions.h"
#include "VGlobal.h"
#include <qtabbar.h>
#include <qvariant.h>
#include "VSaveQuestion.h"

VCenterTabWidget::VCenterTabWidget(QWidget* parent, VBackgroundSystem* bsystem)
	: VTabWidget(parent)
{
	_bsystem = bsystem;

	// 注意：tab的data放的是一个路径

	// 清空tab
	//this->clear();

	// 设置关闭按钮
	this->setTabsClosable(true);

	// 初始化链接
	init_connect();

	// 初始化提示窗口
	init_call_tip_widget();

	// 设置不可被隐藏
	this->setHide(false);

	connect(this, &VCenterTabWidget::signalCurrentWidgetChanged, this, &VCenterTabWidget::onCurrentWidgetChanged);
}

VCenterTabWidget::~VCenterTabWidget()
{
	VGlobal::input_tip->close();
	VGlobal::parameter_tip->close();
	VGlobal::mouse_hover_tip->close();
}

void VCenterTabWidget::open_file(QString path)
{
	if (is_open_file(path))
	{
		change_to_path(path);
		return;
	}

	QString text = VFunctions::read_file_text(path);

	// 创建 scintilla
	VScintillaEx* scintilla = new VScintillaEx(nullptr, path, text, 0);
	scintilla_connect(scintilla);
	scintilla->update_text();

	int index = this->addTab(QFileInfo(path).fileName(), scintilla);
	this->setTabData(index, QVariant::fromValue(path));
	//this->tabBar()->setTabData(index, QVariant::fromValue(path));
	this->setCurrentIndex(index);
	//emit signal_update_file_text(path, text);

}

bool VCenterTabWidget::is_open_file(QString path)
{
	if (get_index(path) != -1)
		return true;
	return false;
}

bool VCenterTabWidget::change_to_path(QString path)
{
	int index = get_index(path);
	if (index == -1)
		return false;
	this->setCurrentIndex(index);
	this->widget(index)->setFocus();
}

int VCenterTabWidget::get_index(QString path)
{
	for (int i = 0; i < this->count(); i++) {
		if (this->tabData(i).value<QString>() == path)
			return i;
	}
	return -1;
}

void VCenterTabWidget::scintilla_connect(VScintillaEx* scintilla)
{
	QObject::connect(scintilla, &VScintillaEx::signal_inpout_tip, _bsystem, &VBackgroundSystem::slot_input_tip);
	QObject::connect(scintilla, &VScintillaEx::signal_function_parameter_tip, _bsystem, &VBackgroundSystem::slot_parameter_calltip);
	QObject::connect(scintilla, &VScintillaEx::signal_mouse_hover_tip, _bsystem, &VBackgroundSystem::slot_mouse_hover_calltip);
	QObject::connect(scintilla, &VScintillaEx::signal_file_tip, _bsystem, &VBackgroundSystem::slot_file_calltip);
	QObject::connect(scintilla, &VScintillaEx::signal_update_file_text, _bsystem, &VBackgroundSystem::slot_update_file_data);
	QObject::connect(scintilla, &VScintillaEx::signal_update_file_last_modify_time, _bsystem, &VBackgroundSystem::slot_set_file_last_time);
	QObject::connect(scintilla, &VScintillaEx::signal_reload_file, _bsystem, &VBackgroundSystem::slot_reload_file);
	QObject::connect(scintilla, &VScintillaEx::signal_set_title, this, &VCenterTabWidget::slot_set_title);
	QObject::connect(scintilla, &VScintillaEx::signal_select_word, _bsystem, &VBackgroundSystem::slot_select_word);
	QObject::connect(scintilla, &VScintillaEx::signal_jump_request, _bsystem, &VBackgroundSystem::slot_jump_request);
	QObject::connect(scintilla, &VScintillaEx::signal_hide_tip, this, &VCenterTabWidget::slot_hide_tip);
	QObject::connect(scintilla, &VScintillaEx::signal_append_navigation, this, &VCenterTabWidget::slot_append_navigation);
	QObject::connect(scintilla, &VScintillaEx::signal_scintilla_update_info, this, &VCenterTabWidget::slot_scintilla_update_info);
}

void VCenterTabWidget::init_connect()
{
	connect(this->tabBar(), &QTabBar::tabCloseRequested, this, &VCenterTabWidget::on_tabCloseRequested);

	// 后台的链接
	QObject::connect(_bsystem, &VBackgroundSystem::signals_calltip, this, &VCenterTabWidget::slot_show_input_calltip);
	QObject::connect(_bsystem, &VBackgroundSystem::signals_parameter_calltip, this, &VCenterTabWidget::slot_show_function_parameter_calltip);
	QObject::connect(_bsystem, &VBackgroundSystem::signal_mouse_hover_calltip, this, &VCenterTabWidget::slot_show_mouse_hover_calltip);
	QObject::connect(_bsystem, &VBackgroundSystem::signal_jump, this, &VCenterTabWidget::slot_jump);
}

void VCenterTabWidget::advance()
{
	if (_navigation_index < _navigation_list.count() - 1)
	{
		_navigation_index++;
		//        ui->tabwidget->open_file(_navigation_list.at(_navigation_index).path);
		//        qDebug() << _navigation_list.at(_navigation_index).path;
		jump_to(_navigation_list.at(_navigation_index).path,
			_navigation_list.at(_navigation_index).line,
			_navigation_list.at(_navigation_index).pos,
			false);
	}
}

void VCenterTabWidget::retreat()
{
	if (_navigation_index > 0)
	{
		_navigation_index--;
		//        ui->tabwidget->open_file(_navigation_list.at(_navigation_index).path);
		jump_to(_navigation_list.at(_navigation_index).path,
			_navigation_list.at(_navigation_index).line,
			_navigation_list.at(_navigation_index).pos,
			false);
	}
}

void VCenterTabWidget::saveAll()
{
	
	for(int i=0; i<this->count(); i++){
		VScintillaEx* scintilla = qobject_cast<VScintillaEx*>(this->widget(i));
		if(scintilla && scintilla->_modify){
			scintilla->save();
		}
	}
}

void VCenterTabWidget::undo()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if(scintilla)
		scintilla->undo();
}

void VCenterTabWidget::redo()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla)
		scintilla->redo();
}

void VCenterTabWidget::cut()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla)
		scintilla->cut();
}

void VCenterTabWidget::copy()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla)
		scintilla->copy();
}

void VCenterTabWidget::paste()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla)
		scintilla->paste();
}

void VCenterTabWidget::comment()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla){
		int cursor_of_line = scintilla->cursorOfLine();
		int anchor_of_line = scintilla->anchorOfLine();
		int start_line = 0;
		int end_line = 0;
		if (cursor_of_line > anchor_of_line)
		{
			start_line = anchor_of_line;
			end_line = cursor_of_line;
		}
		else
		{
			start_line = cursor_of_line;
			end_line = anchor_of_line;
		}

		for (auto i = start_line; i <= end_line; i++)
		{
			int indent = scintilla->indentation(i);
			int line_start_pos = scintilla->lineStartPos(i);
			scintilla->insertText(line_start_pos + indent / scintilla->tabWidth(), "//");
		}

		if (start_line != end_line)
		{
			int start_pos = scintilla->lineStartPos(start_line);
			int end_pos = scintilla->lineEndPos(end_line);
			scintilla->setSelectStartPos(start_pos);
			scintilla->setSelectEndPos(end_pos);
		}
	}
}

void VCenterTabWidget::uncomment()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla) {
		int cursor_of_line = scintilla->cursorOfLine();
		int anchor_of_line = scintilla->anchorOfLine();
		int start_line = 0;
		int end_line = 0;
		if (cursor_of_line > anchor_of_line)
		{
			start_line = anchor_of_line;
			end_line = cursor_of_line;
		}
		else
		{
			start_line = cursor_of_line;
			end_line = anchor_of_line;
		}

		for (auto i = start_line; i <= end_line; i++)
		{
			QString s = scintilla->text(i);
			int pos = s.indexOf("//");
			if (pos != -1)
			{
				int line_start_pos = scintilla->lineStartPos(i);
				scintilla->deleteRange(line_start_pos + pos, 2);
			}
		}
	}
}

void VCenterTabWidget::backTab()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla)
		scintilla->backTab();
}

void VCenterTabWidget::Tab()
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla)
		scintilla->Tab();
}

bool VCenterTabWidget::close_query()
{
	QStringList modifyPaths;
	for(int i=0; i<this->count(); i++){
		auto scintilla = qobject_cast<VScintillaEx*>(this->widget(i));
		if(scintilla && scintilla->_modify){
			modifyPaths.append(tabData(i).value<QString>());
		}
	}

	if(modifyPaths.count() == 0){
		return true;
	}

	VSaveQuestion dlg(this, modifyPaths);
	int result = dlg.exec();
	if(result == QDialog::Accepted) {
		foreach(QString path, dlg._save_paths)
		{
			auto scintilla = qobject_cast<VScintillaEx*>(this->widget(get_index(path)));
			if (scintilla) {
				scintilla->save();
			}
		}
		return true;
	}

	return false;
}

bool VCenterTabWidget::close_paths(QStringList paths)
{
	QStringList modifyPaths;
	foreach(QString path, paths){
		if(is_open_file(path)){
			auto scintilla = qobject_cast<VScintillaEx*>(this->widget(get_index(path)));
			if(scintilla && scintilla->_modify){
				modifyPaths.append(path);
			}
		}
	}

	if(modifyPaths.count() != 0){
		VSaveQuestion dlg(this, modifyPaths);
		int result = dlg.exec();
		if (result == QDialog::Accepted){
			foreach(QString path, dlg._save_paths)
			{
				auto scintilla = qobject_cast<VScintillaEx*>(this->widget(get_index(path)));
				if (scintilla) {
					scintilla->save();
				}
			}
		}else{
			return false;
		}
	}

	foreach(QString path, paths){
		int index = get_index(path);
		if(index != -1){
			this->removeTab(index);
		}
	}

	return true;
}

void VCenterTabWidget::on_tabCloseRequested(int index)
{
	//QString path = this->tabBar()->tabData(index).value<QString>();
	VScintillaEx* scintilla = qobject_cast<VScintillaEx*>(this->widget(index));
	if(scintilla == nullptr){
		this->removeTab(index);
		return;
	}

	if (scintilla && scintilla->save_question()) {
		this->removeTab(index);
	}
}

void VCenterTabWidget::slot_show_input_calltip(QList<VWords*> list) {

	// 释放内存
	for (int i = 0; i < VGlobal::input_tip->count(); i++)
	{
		auto item = VGlobal::input_tip->item(i);
		VWords* ptr = (VWords*)(item->data(Qt::UserRole).value<void*>());
		if (ptr != nullptr)
		{
			delete ptr;
			item->setData(Qt::UserRole, QVariant::fromValue((void*)nullptr));
		}
	}

	// 判断当前是否打开文件
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla == nullptr) {
		VGlobal::input_tip->hide();
		return;
	}


	VGlobal::input_tip->clear();

	foreach(VWords * p_word, list)
	{
		QListWidgetItem* item = new QListWidgetItem(VGlobal::input_tip);
		item->setIcon(QIcon(get_calltip_icon(p_word->_kind)));
		item->setText(calltip_item_text(p_word));
		item->setData(Qt::UserRole, QVariant::fromValue(static_cast<void*>(p_word)));
	}

	if (VGlobal::input_tip->count() > 0)
	{
		int cursor_pos = scintilla->SendScintilla(QsciScintilla::SCI_GETCURRENTPOS);
		QPoint point;

		point.setX(scintilla->SendScintilla(QsciScintilla::SCI_POINTXFROMPOSITION, 0, cursor_pos));
		point.setY(scintilla->SendScintilla(QsciScintilla::SCI_POINTYFROMPOSITION, 0, cursor_pos)
			+ scintilla->SendScintilla(QsciScintilla::SCI_TEXTHEIGHT, 0) + 2);

		int count;
		count = VGlobal::input_tip->count() > 10 ? 10 : VGlobal::input_tip->count();

		VGlobal::input_tip->move(scintilla->mapToGlobal(point));
		VGlobal::input_tip->setCurrentRow(0);

		VGlobal::input_tip->setMinimumWidth(VGlobal::input_tip->sizeHintForColumn(0) +
			2 * VGlobal::input_tip->frameWidth() + 35);
		VGlobal::input_tip->setMinimumHeight(VGlobal::input_tip->sizeHintForRow(0) * count
			+ 2 * VGlobal::input_tip->frameWidth());
		VGlobal::input_tip->setMaximumHeight(VGlobal::input_tip->sizeHintForRow(0) * count
			+ 2 * VGlobal::input_tip->frameWidth());

		// 设置位置大小
//        VGlobal::input_tip->setGeometry(scintilla->mapToGlobal(point).x,
//                                         scintilla->mapToGlobal(point).y,
//                                         0, (VGlobal::input_tip->sizeHintForRow(0) *
//                                         VGlobal::input_tip->count() + 2 *
//                                         VGlobal::input_tip->frameWidth()));

		VGlobal::input_tip->show();
		if (scintilla->hasFocus() == false)
		{
			VGlobal::input_tip->hide(); VGlobal::input_tip->hide();
		}
	}
	else
	{
		VGlobal::input_tip->hide(); VGlobal::input_tip->hide();
	}

}

void VCenterTabWidget::slot_show_function_parameter_calltip(QString text, int pos)
{
	VGlobal::parameter_tip->setText(text);
	VGlobal::parameter_tip->adjustSize();

	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla == nullptr) {
		return;
	}

	QPoint point;
	point.setX(scintilla->SendScintilla(QsciScintilla::SCI_POINTXFROMPOSITION, 0, pos));
	point.setY(scintilla->SendScintilla(QsciScintilla::SCI_POINTYFROMPOSITION, 0, pos) -
		VGlobal::parameter_tip->height());
	VGlobal::parameter_tip->move(scintilla->mapToGlobal(point));
	VGlobal::parameter_tip->show();
}

void VCenterTabWidget::slot_show_mouse_hover_calltip(QString text, int pos)
{
	VGlobal::mouse_hover_tip->setText(text);
	VGlobal::mouse_hover_tip->adjustSize();

	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla == nullptr) {
		VGlobal::mouse_hover_tip->hide();
		return;
	}

	// 如果菜单列表是可见的
	// 则中止显示
	if (scintilla->_content_menu.isVisible())
	{
		return;
	}

	QPoint point;
	point.setX(scintilla->SendScintilla(QsciScintilla::SCI_POINTXFROMPOSITION, 0, pos));
	point.setY(scintilla->SendScintilla(QsciScintilla::SCI_POINTYFROMPOSITION, 0, pos) +
		scintilla->textHeight(scintilla->posOfLine(pos))
	);

	VGlobal::mouse_hover_tip->move(scintilla->mapToGlobal(point));
	VGlobal::mouse_hover_tip->show();
}

void VCenterTabWidget::slot_set_title(QString path, QString title)
{
	int index = get_index(path);
	if (index == -1)
		return;
	this->tabBar()->setTabText(index, title);
}

void VCenterTabWidget::slot_scintilla_update_info(QString path, int line, int pos, int lines)
{
	emit signal_scintilla_update_info(path, line, pos, lines);
}

void VCenterTabWidget::slot_jump(QString path, int line_number)
{
	line_number--;
	jump_to(path, line_number);
	//    ui->tabwidget->open_file(path);
	//    ui->tabwidget->jump(path, line_number);
}

void VCenterTabWidget::slot_hide_tip(int mode)
{
	if (mode & VGlobal::TipType::TIP_INPUT)
	{
		VGlobal::input_tip->hide();
	}
	if (mode & VGlobal::TipType::TIP_PARAMETER)
	{
		VGlobal::parameter_tip->hide();
	}
	if (mode & VGlobal::TipType::TIP_MOUSERHOVER)
	{
		VGlobal::mouse_hover_tip->hide();
	}
}

bool VCenterTabWidget::jump_to(QString path, int line, int pos, bool append)
{
	if (line < 0 && pos < 0)
	{
		return false;
	}

	open_file(path);
	change_to_path(path);

	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla == nullptr) return false;

	scintilla->setFocus();
	if (pos == -1)
	{
		scintilla->setSelect(scintilla->lineStartPos(line), scintilla->lineStartPos(line));
	}
	else
	{
		scintilla->setSelect(pos, pos);
	}
	if (append)
	{
		scintilla->append_navigation();
	}

	return true;
}

QString VCenterTabWidget::get_calltip_icon(int type)
{
	QString result;
	switch (type)
	{
	case VWords::KIND::PROTOTYPE:
	case VWords::KIND::FUNCTION:
		result = VGlobal::icon_path.value("function");
		break;
	case VWords::KIND::KEYWORD:
		result = VGlobal::icon_path.value("keyword");
		break;
	case VWords::KIND::ENUM:
		result = VGlobal::icon_path.value("enum");
		break;
	case VWords::KIND::ENUMERATOR:
		result = VGlobal::icon_path.value("enumerator");
		break;
	case VWords::KIND::TYPEDEF:
		result = VGlobal::icon_path.value("typedef");
		break;
	case VWords::KIND::STRUCT:
		result = VGlobal::icon_path.value("strcut");
		break;
	case VWords::KIND::UNION:
		result = VGlobal::icon_path.value("union");
		break;
	case VWords::KIND::MEMBER:
		result = VGlobal::icon_path.value("menber");
		break;
	case VWords::KIND::MARCO:
		result = VGlobal::icon_path.value("define");
		break;
	case VWords::KIND::PARAMETER:
		result = VGlobal::icon_path.value("parameter");
		break;
	case VWords::KIND::LOCAL:
		result = VGlobal::icon_path.value("local");
		break;
	case VWords::KIND::VARIABLE:
		result = VGlobal::icon_path.value("global");
		break;
	case VWords::KIND::FILE:
		result = VGlobal::icon_path.value("file_h");
		break;
	case VWords::KIND::FOLDER:
		result = VGlobal::icon_path.value("folder");
		break;
	case VWords::KIND::TEMPLATE:
		result = VGlobal::icon_path.value("template");
		break;
	case VWords::KIND::LABEL:
		result = VGlobal::icon_path.value("label");
		break;
	default:
		break;
	}
	return result;
}

QString VCenterTabWidget::calltip_item_text(VWords* p_word)
{
	QString result;
	switch (p_word->_kind)
	{
	case VWords::KIND::MARCO:
		result = p_word->_name + " : " + "宏定义";
		break;
	case VWords::KIND::PARAMETER:
		result = p_word->_name + " : " + p_word->_type_name;
		break;
	case VWords::KIND::LOCAL:
		result = p_word->_name + " : " + p_word->_type_name;
		break;
	case VWords::KIND::VARIABLE:
		result = p_word->_name + " : " + p_word->_type_name;
		break;
	default:
		result = p_word->_name;
		break;
	}
	return result;
	return QString();
}

void VCenterTabWidget::init_call_tip_widget()
{
	VGlobal::input_tip = new VInputListWidget();
	VGlobal::input_tip->setParent(0, Qt::Popup);
	VGlobal::input_tip->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::SubWindow | Qt::Popup);
	VGlobal::input_tip->setAttribute(Qt::WA_ShowWithoutActivating, true);
	VGlobal::input_tip->setStyleSheet(this->styleSheet());
	VGlobal::input_tip->setFont(this->font());
	VGlobal::input_tip->hide();


	VGlobal::parameter_tip = new QLabel();
	VGlobal::parameter_tip->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::SubWindow | Qt::Popup);
	VGlobal::parameter_tip->setAttribute(Qt::WA_ShowWithoutActivating, true);
	VGlobal::parameter_tip->setObjectName("parameter_calltip_label");
	VGlobal::parameter_tip->setStyleSheet(this->styleSheet());
	VGlobal::parameter_tip->hide();
	VGlobal::parameter_tip->setFont(this->font());

	VGlobal::mouse_hover_tip = new QLabel();
	VGlobal::mouse_hover_tip->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::SubWindow | Qt::Popup);
	VGlobal::mouse_hover_tip->setAttribute(Qt::WA_ShowWithoutActivating, true);
	VGlobal::mouse_hover_tip->setObjectName("mouse_hover_calltip_label");
	VGlobal::mouse_hover_tip->setStyleSheet(this->styleSheet());
	VGlobal::mouse_hover_tip->setFont(this->font());
	VGlobal::mouse_hover_tip->hide();

	QObject::connect(VGlobal::input_tip, &VInputListWidget::signal_input_word, this, &VCenterTabWidget::slot_input_word_transfer);
}

void VCenterTabWidget::onCurrentWidgetChanged(QWidget* w)
{
	VScintillaEx* scintilla = qobject_cast<VScintillaEx*>(w);
	if(w == nullptr){
		emit signal_scintilla_update_info("", -1, -1, -1);
	}
}

void VCenterTabWidget::slot_input_word_transfer(VWords* word)
{
	auto scintilla = qobject_cast<VScintillaEx*>(this->currentWidget());
	if (scintilla == nullptr) return;
	scintilla->input_word(word);
}

void VCenterTabWidget::slot_append_navigation(QString path, int line, int pos)
{
	append_navigation(path, line, pos);
}

void VCenterTabWidget::append_navigation(QString path, int line, int pos)
{
	// 判断路径是否存在
	// 不存在则返回
	if (path.length() == 0)
	{
		return;
	}

	// 判断 index 是否在中途
	// 如果在中途则清楚后面的内容
	int count = _navigation_list.count() - 1 - _navigation_index;
	if (count > 0)
	{
		while (count--)
		{
			_navigation_list.removeAt(_navigation_index + 1);
		}
	}

	// 判断是否和上一个的内容相同
	// 如果相同则清楚当前条
	// 确保最新信息
	if (_navigation_list.count() > 0)
	{
		if (_navigation_list.at(_navigation_index).line == line
			&& _navigation_list.at(_navigation_index).path == path)
		{
			_navigation_list.removeAt(_navigation_index);
		}
	}


	NavigationInfo nav;
	nav.line = line;
	nav.path = path;
	nav.pos = pos;
	_navigation_list.append(nav);
	_navigation_index = _navigation_list.count() - 1;
}